/*
 * Copyright (C) 2021 Huawei Device Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.tonyodev.fetchapp.ability;

import ohos.aafwk.ability.Ability;
import ohos.aafwk.content.Intent;
import ohos.agp.components.Button;
import ohos.agp.components.Component;
import ohos.agp.components.DependentLayout;
import ohos.agp.components.ProgressBar;
import ohos.agp.components.Text;
import ohos.agp.text.Font;
import ohos.agp.utils.Color;
import ohos.agp.window.dialog.ToastDialog;
import ohos.bundle.IBundleManager;
import ohos.utils.Pair;

import com.tonyodev.fetch2.AbstractFetchListener;
import com.tonyodev.fetch2.Download;
import com.tonyodev.fetch2.Error;
import com.tonyodev.fetch2.FetchErrorUtils;
import com.tonyodev.fetch2.FetchListener;
import com.tonyodev.fetch2.Request;
import com.tonyodev.fetch2rx.RxFetch;
import com.tonyodev.fetchapp.Data;
import com.tonyodev.fetchapp.ResourceTable;
import com.tonyodev.fetchapp.snackbar.SnackBar;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Set;
import java.util.logging.Level;
import java.util.logging.Logger;

import io.reactivex.disposables.Disposable;
import timber.log.Timber;

import static ohos.security.SystemPermission.WRITE_USER_STORAGE;

/**
 *
 *
 * @since 2021-05-20
 */
public class GameFilesAbility extends Ability {
    private static final int STORAGE_PERMISSION_CODE = 400;

    private static final int groupId = 12;

    private Component mainView;
    private Text labelTextView;
    private Text progressTextView;
    private ProgressBar progressBar;
    private Button startButton;
    private final HashMap<Integer, Integer> fileProgressMap = new HashMap<>();


    private RxFetch rxFetch;
    private Disposable enqueueDisposable;
    private Disposable resumeDisposable;

    @Override
    public void onStart(Intent intent) {
        super.onStart(intent);
        getWindow().setStatusBarColor(Color.getIntColor("#303f9f"));
        super.setUIContent(ResourceTable.Layout_ability_game_files);
        initView();
        rxFetch = RxFetch.Impl.getDefaultRxInstance();
        reset();
    }

    private void initView(){
        mainView = (DependentLayout) findComponentById(ResourceTable.Id_ability_loading);
        labelTextView = (Text) findComponentById(ResourceTable.Id_labelTextView);
        progressTextView = (Text) findComponentById(ResourceTable.Id_progressTextView);
        progressBar = (ProgressBar) findComponentById(ResourceTable.Id_progressBar);
        startButton = (Button) findComponentById(ResourceTable.Id_startButton);

        startButton.setClickedListener(new Component.ClickedListener() {
            @Override
            public void onClick(Component component) {
                String label = startButton.getText().toString();
                if (label.equals(getString(ResourceTable.String_reset))){
                    rxFetch.deleteAll();
                    reset();
                }else {
                    startButton.setVisibility(Component.HIDE);
                    labelTextView.setText(ResourceTable.String_fetch_started);
                    checkStoragePermission();
                }
            }
        });
    }

    @Override
    protected void onActive() {
        super.onActive();
        rxFetch.addListener(fetchListener);
        resumeDisposable = rxFetch.getDownloadsInGroup(groupId).asFlowable().subscribe(downloads -> {
            for (Download download : downloads) {
                if (fileProgressMap.containsKey(download.getId())) {
                    fileProgressMap.put(download.getId(), download.getProgress());
                    updateUIWithProgress();
                }
            }
            Logger.getGlobal().log(Level.INFO,"..111111......onActive");

        }, throwable -> {
            final Error error = FetchErrorUtils.getErrorFromThrowable(throwable);
            Timber.d("GamesFilesActivity Error: %1$s", error);
        });
    }

    @Override
    protected void onInactive() {
        super.onInactive();
        rxFetch.removeListener(fetchListener);
    }

    @Override
    protected void onStop() {
        super.onStop();
        rxFetch.deleteAll();
        rxFetch.close();
        if (enqueueDisposable != null && !enqueueDisposable.isDisposed()) {
            enqueueDisposable.dispose();
        }
        if (resumeDisposable != null && !resumeDisposable.isDisposed()) {
            resumeDisposable.dispose();
        }
    }

    private void checkStoragePermission() {
        // 权限申请
        List<String> permissionsToRequest = new ArrayList<>();
        String[] permissions = new String[]{WRITE_USER_STORAGE};
        for (String permission : permissions) {
            if (verifyCallingPermission(permission) != IBundleManager.PERMISSION_GRANTED) {
                // 应用未被授予权限
                if (canRequestPermission(permission)) { // 是否可以申请弹框授权 如果可以就把权限添加到列表中
                    permissionsToRequest.add(permission);
                }
            }
        }

        if (!permissionsToRequest.isEmpty()) { //
            requestPermissionsFromUser(permissions, STORAGE_PERMISSION_CODE); // 说明有权限没有申请
        } else {
            enqueueFiles();
        }
    }

    @Override
    public void onRequestPermissionsFromUserResult(int requestCode, String[] permissions, int[] grantResults) {
        super.onRequestPermissionsFromUserResult(requestCode, permissions, grantResults);
        if (requestCode == STORAGE_PERMISSION_CODE) {
            enqueueFiles();
        } else {
            new ToastDialog(this).setText(getContext().getString(ResourceTable.String_fetch_started)).show();
            reset();
        }
    }

    private void enqueueFiles() {
        final List<Request> requestList = Data.getGameUpdates(this);
        for (Request request : requestList) {
            request.setGroupId(groupId);
        }
        enqueueDisposable = rxFetch.enqueue(requestList).asFlowable().subscribe(updatedRequests -> {
            for (Pair<Request, Error> request : updatedRequests) {
                fileProgressMap.put(request.f.getId(), 0);
                updateUIWithProgress();
            }
        }, throwable -> {
            final Error error = FetchErrorUtils.getErrorFromThrowable(throwable);
            Timber.d("GamesFilesActivity Error: %1$s", error);
        });
    }

    private void reset() {
        rxFetch.deleteAll();
        fileProgressMap.clear();
        progressBar.setProgressValue(0);
        progressTextView.setText("");
        labelTextView.setText(ResourceTable.String_start_fetching);
        startButton.setText(ResourceTable.String_start);
        startButton.setVisibility(Component.VISIBLE);
    }

    private void updateUIWithProgress() {

        final int totalFiles = fileProgressMap.size();
        final int completedFiles = getCompletedFileCount();

        progressTextView.setText(getContext().getString(ResourceTable.String_complete_over,completedFiles,totalFiles));
        final int progress = getDownloadProgress();
        Logger.getGlobal().log(Level.INFO,"...00000000.......completedFiles="+completedFiles+"......totalFiles="+totalFiles+".....progress="+progress);
        progressBar.setProgressValue(progress);
        if (completedFiles == totalFiles) {
            labelTextView.setText(getString(ResourceTable.String_fetch_done));
            startButton.setText(getString(ResourceTable.String_reset));
            startButton.setVisibility(Component.VISIBLE);
        }
    }

    private int getDownloadProgress() {
        int currentProgress = 0;
        final int totalProgress = fileProgressMap.size() * 100;
        final Set<Integer> ids = fileProgressMap.keySet();

        for (int id : ids) {
            currentProgress += fileProgressMap.get(id);
        }
        currentProgress = (int) (((double) currentProgress / (double) totalProgress) * 100);
        return currentProgress;
    }

    private int getCompletedFileCount() {
        int count = 0;
        final Set<Integer> ids = fileProgressMap.keySet();
        for (int id : ids) {
            int progress = fileProgressMap.get(id);
            if (progress == 100) {
                count++;
            }
        }
        return count;
    }

    private final FetchListener fetchListener = new AbstractFetchListener() {

        @Override
        public void onCompleted(Download download) {
            super.onCompleted(download); fileProgressMap.put(download.getId(), download.getProgress());
            updateUIWithProgress();

        }

        @Override
        public void onError(Download download, Error error, Throwable throwable) {
            super.onError(download, error, throwable);
            reset();
            new SnackBar.Builder(GameFilesAbility.this,mainView)
                .withMessage(getString(ResourceTable.String_game_download_error))
                .show();
        }

        @Override
        public void onQueued(Download download, boolean waitingOnNetwork) {

        }

        @Override
        public void onProgress(Download download, long etaInMilliSeconds, long downloadedBytesPerSecond) {
            fileProgressMap.put(download.getId(), download.getProgress());
            updateUIWithProgress();
        }
    };
}
